function xhr( options ){
      // options { method : ? , url : ? , data : ? , callback ? }
      var xhr = new XMLHttpRequest();
      // 数据问题 : data 怎么处理 ? 
      // "key=value&key2=value2"
      // { key : value , key2 : value2 }  √ ; 
      // 让 xhr 在调用的时候以对象的形式传入data，我们把data对象的格式转换成字符串格式; 

      // 判断options.data是对象再去进行字符串拼接
      // js之中判断对象很麻烦; 
      // - typeof判断data为object 之后还需要判断 data不为null,同时判断data不是数组; 
      if( typeof options.data === "object" && options.data !== null && !(options.data instanceof Array) ){
            var data = "";
            for(var key in options.data){
                  // &key=value 
                  data += "&"+key + "=" + options.data[key];
            }
            // 我们拼接好的字符串前面多了一个& 所以我们删除掉开头的& ; 
            data = data.slice(1);
      }
    


      // 如果此时的请求类型是GET，同时data里面有数据，那么我们把数据拼接到 URL之中; 
      if( data && options.method.toUpperCase() === "GET"){
            options.url += "?" + data ; 
      }
      xhr.open( options.method , options.url );

      // 如果此时的请求是POST，那么我们需要进行请求头设置; 
      if(data && options.method.toUpperCase() === "POST"){
            xhr.setRequestHeader("content-type" , "application/x-www-form-urlencoded");
            xhr.send( data );
      }else{
            xhr.send();
      }

      xhr.onload = function(){
            // 为了让函数的调用更为稳定; 
            // 判定状态码为2开头再去调用回调函数; 
            // 状态码 : xhr.status 
            if( /^2/.test(xhr.status) ){
                  // 在封装之中调用函数必须先去判定一下函数是否存在; 
                  var data = xhr.responseText;
                  // 如果JSON.parse解析报错，那么就会走catch语句代码; 
                  // - 使用try catch 语句不会让程序因为报错导致代码终止; 
                  try{
                      data = JSON.parse(data); 
                  }catch( e ){
                      data = xhr.responseText;
                  }

                  typeof options.callback === "function" ? options.callback( data ) : "";
            }
      }
}     